# Copyright 2023 Iguazio
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os

import pytest

import mlrun
from mlrun.config import config
from mlrun.secrets import SecretsStore


@pytest.fixture
def reset_config():
    # Save the original configuration value
    original_prefix = config.secret_stores.kubernetes.env_variable_prefix
    yield
    # Revert the configuration after the test
    config.secret_stores.kubernetes.env_variable_prefix = original_prefix


@pytest.fixture(autouse=True)
def clean_env(monkeypatch):
    """Ensure clean environment for each test."""
    saved = dict(os.environ)
    for key in list(os.environ.keys()):
        monkeypatch.delenv(key, raising=False)
    yield
    os.environ.clear()
    os.environ.update(saved)


def reverser(key):
    return key[::-1]


def test_get_secret_from_env(reset_config):
    # Set the prefix to "MLRUN_K8S_SECRET__" as this test validates behavior with a defined prefix,
    # while the default configuration has been changed to empty.
    config.secret_stores.kubernetes.env_variable_prefix = "MLRUN_K8S_SECRET__"

    key = "SOME_KEY"
    value = "SOME_VALUE"
    project_secret_value = "SOME_OTHER_VALUE"
    override_value = "SOME_OVERRIDE"

    # Use an env variable
    os.environ[key] = value
    assert mlrun.get_secret_or_env(key) == value

    os.environ[SecretsStore.k8s_env_variable_name_for_secret(key)] = (
        project_secret_value
    )
    # Project secrets should not override directly set env variables
    assert mlrun.get_secret_or_env(key) == value

    del os.environ[key]
    assert mlrun.get_secret_or_env(key) == project_secret_value

    # Use a local override dictionary
    local_secrets = {key: override_value}
    assert mlrun.get_secret_or_env(key, secret_provider=local_secrets) == override_value

    # Use a callable
    assert mlrun.get_secret_or_env(key, secret_provider=reverser) == reverser(key)

    # Use a SecretsStore
    store = SecretsStore()
    store.add_source("inline", local_secrets)
    assert mlrun.get_secret_or_env(key, secret_provider=store) == override_value

    # Verify that default is used if nothing else is found
    assert (
        mlrun.get_secret_or_env(
            "SOME_GIBBERISH",
            secret_provider=store,
            default="not gibberish",
        )
        == "not gibberish"
    )


def test_json_list_used_when_no_direct_env(monkeypatch):
    monkeypatch.setenv(
        "SECRETS_JSON",
        json.dumps(
            [
                {"name": "OTHER_KEY", "value": "IGNORED"},
                {"name": "MY_KEY", "value": "FROM_JSON"},
            ]
        ),
    )
    assert mlrun.get_secret_or_env("MY_KEY") == "FROM_JSON"


def test_direct_env_over_json_list(monkeypatch):
    monkeypatch.setenv("MY_KEY", "FROM_ENV")
    monkeypatch.setenv(
        "SECRETS_JSON",
        json.dumps([{"name": "MY_KEY", "value": "FROM_JSON"}]),
    )
    # direct env must win over JSON list
    assert mlrun.get_secret_or_env("MY_KEY") == "FROM_ENV"


def test_non_json_env_ignored(monkeypatch):
    # non-JSON should not crash or match
    monkeypatch.setenv("BAD_ENV", "not-json")
    assert mlrun.get_secret_or_env("MY_KEY", default="DEFAULT") == "DEFAULT"
